/*!
   \file

   \brief
      Windows implementation of memory-mapped file.

   © 2011 Mark W. Gabby II

   This file is part of Rock Hunter.

   Rock Hunter is free software: you can redistribute it and/or modify it under the terms of the
   GNU General Public License as published by the Free Software Foundation, either version 3 of the
   License, or (at your option) any later version.

   Rock Hunter is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without
   even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
   General Public License for more details.

   You should have received a copy of the GNU General Public License along with Rock Hunter.
   If not, see <http://www.gnu.org/licenses/>.
*/
#include "Util/MemMappedFile.hpp"

#include <map>

#define WIN32_LEAN_AND_MEAN
#define WINVER 0x501 // Windows XP
#include <windows.h>

#include "Systems/ErrorManager/ErrorManager.hpp"

static std::map<tFileID, HANDLE> gFileIDToFileHandle;
static tFileID gNextFileID = 0;

MemMappedFile::MemMappedFile()
{
   fileBase = 0;
   id = gNextFileID++;
   AssertError( gNextFileID != kNull32, "Out of file IDs. You may want to consider a more robust allocation "
                "method." );
}

std::map<tFileID, HANDLE> FileIDToFileHandle;

uint8_t * MemMappedFile::OpenRead( const char * Filename )
{
   // Open the file. Read-only. Allow it to be read by others.
   HANDLE FileHandle = CreateFile( Filename, GENERIC_READ, FILE_SHARE_READ,
                                   0, OPEN_EXISTING, 0, 0 );

   if ( FileHandle == INVALID_HANDLE_VALUE )
   {
      return 0;
   }

   gFileIDToFileHandle[id] = FileHandle;

   fileSizeBytes = GetFileSize( FileHandle, NULL );

   // Create a file mapping.
   HANDLE FileMapping = CreateFileMapping( FileHandle, 0, PAGE_READONLY,
                                           0, 0, 0 );

   fileBase = ( uint8_t * ) MapViewOfFile( FileMapping, FILE_MAP_READ,
                                           0, 0, 0 );

   // Will be NULL on failure.
   return fileBase;

}

uint32_t MemMappedFile::GetFileSizeBytes()
{
   return fileSizeBytes;
}
void MemMappedFile::Close()
{
   fileBase = 0;
   HANDLE & FileHandleRef = gFileIDToFileHandle[id];
   if ( FileHandleRef != INVALID_HANDLE_VALUE )
   {
      CloseHandle( FileHandleRef );
   }
   FileHandleRef = INVALID_HANDLE_VALUE;
}

uint8_t * MemMappedFile::GetBaseAddress()
{
   return fileBase;
}

MemMappedFile::~MemMappedFile()
{
   Close();
}
